package org.zjh.utils;

import org.zjh.common.PokerIndex;
import org.zjh.common.PokerType;
import org.zjh.controller.GameController;
import org.zjh.controller.timer.MoveObjTimer;
import org.zjh.model.*;
import org.zjh.view.game.GameFrame;
import org.zjh.view.ui.GameUi;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import static org.zjh.common.GameCommon.checkDiscardBoom;


/**
 * @description: TODO
 * @author 郑佳豪
 * @date 2024/10/13 3:26
 * @version 1.0
 */
public class PokerUtil {


    /**
     * 生成牌堆
     * @return 扑克牌集合
     */
    public static ArrayList<Poker> generatePokerBoxList() {
        ArrayList<Poker> pokerBoxList = new ArrayList<>();
        for (int i = 1; i <= 5; i++) {
            for (int j = 1; j <= 13; j++) {
                Poker poker;
                if (i == 5 && j >= 3) {
                    break;
                }
                poker = new Poker(i + "-" + (j + 2), false);

                if (i == 5) {
                    poker.setNumber(j + 13);
                } else {
                    poker.setNumber(j);
                }
                pokerBoxList.add(poker);
            }
        }
        //打乱牌堆
        Collections.shuffle(pokerBoxList);


        return pokerBoxList;
    }


    /**
     * 获得地主牌（牌堆中后三张）
     */
    public static ArrayList getDZPoker() {
        ArrayList<Poker> dzPokerList = GameController.getInstance().getLandOwnerPokerList();
        ArrayList<Poker> pokerBoxList = GameController.getInstance().getPokerBoxList();
        for (int i = 51; i < pokerBoxList.size(); i++) {
            dzPokerList.add(pokerBoxList.get(i));
        }
        return dzPokerList;
    }


    /**
     * 面板画出牌堆
     */
    public static void painPoker() {
        //拿到牌堆集合
        ArrayList<Poker> pokerBoxList = GameController.getInstance().getPokerBoxList();
        //从前面51张中去一张叫分牌
        Poker callPointPoker = pokerBoxList.get(RandomUtil.RANDOM.nextInt(pokerBoxList.size() - 3));
        //设置叫分牌属性
        callPointPoker.setCallPointPoker(true);
        //设置正面朝上
        callPointPoker.setUp(true);
        //叫分牌翻面
        callPointPoker.turnFront();

        //遍历牌堆
        for (int i = 0; i < pokerBoxList.size(); i++) {
            Poker poker = pokerBoxList.get(i);
            //如果是叫分牌 就弹出
            poker.setLocation(300 + i * 5, poker.isCallPointPoker() ? 170 : 200);
            GameUi.gameFrame.getGamePanel().add(poker);
        }
    }


    /**
     * 玩家手牌排序
     * @param player 玩家
     */
    public static void sortPoker(Player player) {
        ArrayList<Poker> pokerList = player.getPokerList();
        pokerList.sort((o1, o2) -> o2.getNumber() - o1.getNumber());
        pokerMove(player);
    }

    /**
     * 卡牌位置移动
     * @param player 玩家
     */
    public static void pokerMove(Player player) {
        Point startPoint = new Point();
        int moveDistanceX = 0, moveDistanceY = 0;
        int size = player.getPokerList().size();
        if (player instanceof RealPlayer) {
            int totalPokerWidth = 35 * size + 35;
            int startX = (GameFrame.WIDTH - totalPokerWidth) / 2;

            startPoint.setLocation(startX, 500);
            moveDistanceX = 35;
        } else if (player == GameController.getInstance().getComputerA()) {
            int totalPokerHeight = 20 * size + 83;
            int startY = (GameFrame.HEIGHT - totalPokerHeight) / 2 - 50;
            startPoint.setLocation(25, startY);
            moveDistanceY = 20;
        } else {
            int totalPokerHeight = 20 * size + 83;
            int startY = (GameFrame.HEIGHT - totalPokerHeight) / 2 - 50;
            startPoint.setLocation(1050, startY);
            moveDistanceY = 20;
        }

        repositionPlayerCards(player, startPoint, moveDistanceX, moveDistanceY);
    }


    /**
     * 玩家卡牌位置重新摆放
     * @param player 玩家
     * @param startPoint 起始位置
     * @param moveDistanceX 移动距离X
     * @param moveDistanceY 移动距离Y
     */
    private static void repositionPlayerCards(Player player, Point startPoint, int moveDistanceX, int moveDistanceY) {
        int len = player.getPokerList().size();

        for (int i = 0; i < len; i++) {
            Poker poker = player.getPokerList().get(i);
            if (player instanceof ComputerPlayer && poker.isUp()) {
                poker.setUp(false);
                poker.turnRear();
            }
            new MoveObjTimer(poker, startPoint.x, startPoint.y, GameUi.gameFrame.getGamePanel());
            startPoint.x += moveDistanceX;
            startPoint.y += moveDistanceY;
            GameUi.gameFrame.getGamePanel().setComponentZOrder(poker, 0);
        }

    }


    /**
     * 移动 出牌集合中的手牌
     * @param player 玩家
     */
    public static void moveDiscardPoker(Player player) {
        ArrayList<Poker> discardPokerList = player.getDiscardPokerList();
        int size = discardPokerList.size();

        if (player instanceof RealPlayer) {
            int totalPokerWidth = 35 * size + 35;
            int startX = (GameFrame.WIDTH - totalPokerWidth) / 2;
            for (int i = 0; i < size; i++) {
                Poker poker = discardPokerList.get(i);
                poker.setLocation(startX + i * 35, 275);
                GameUi.gameFrame.getGamePanel().setComponentZOrder(poker, 0);
            }
        } else if (player instanceof ComputerA) {
            int totalPokerHeight = 20 * size + 83;
            int startY = (GameFrame.HEIGHT - totalPokerHeight) / 2 - 75;
            for (int i = 0; i < size; i++) {
                Poker poker = discardPokerList.get(i);
                poker.setLocation(150, startY + i * 35);
                GameUi.gameFrame.getGamePanel().setComponentZOrder(poker, 0);
            }


        } else {
            int totalPokerHeight = 20 * size + 83;
            int startY = (GameFrame.HEIGHT - totalPokerHeight) / 2 - 75;
            for (int i = 0; i < size; i++) {
                Poker poker = discardPokerList.get(i);
                poker.setLocation(950, startY + i * 35);
                GameUi.gameFrame.getGamePanel().setComponentZOrder(poker, 0);
            }
        }


    }


    /**
     * 设置手牌能被点击
     * @param pokerList 扑克牌集合
     */
    public static void setCanBeClick(ArrayList<Poker> pokerList) {
        for (Poker poker : pokerList) {
            poker.setCanBeClick(true);
        }
    }


    /**
     * 设置手牌不能被点击
     * @param pokerList 扑克牌集合
     */
    public static void setCantBeClick(ArrayList<Poker> pokerList) {
        for (Poker poker : pokerList) {
            poker.setCanBeClick(false);
        }
    }


    /**
     * 重置扑克牌盒中的牌
     * @param pokerList 扑克牌集合
     */
    public static void ResetPokerList(ArrayList<Poker> pokerList) {
        pokerDown(pokerList);
        for (Poker poker : pokerList) {
            //设置可见
            poker.setVisible(true);
            //设置不能被点击
            poker.setCanBeClick(false);
            //设置点击状态 false
            poker.setClicked(false);
            //将叫分牌 取消
            if (poker.isCallPointPoker()) {
                poker.setCallPointPoker(false);
            }
            //重置标识符
            poker.setOwnerId("");
        }
    }

    /**
     * 扑克牌正面朝上
     * @param pokerList 扑克牌集合
     */
    public static void pokerUp(ArrayList<Poker> pokerList) {
        for (Poker poker : pokerList) {
            if (poker.isUp()) {
                continue;
            }
            poker.setUp(true);
            poker.turnFront();
        }
    }

    /**
     * 扑克牌翻面朝上
     * @param pokerList 扑克牌集合
     */
    public static void pokerDown(ArrayList<Poker> pokerList) {
        for (Poker poker : pokerList) {

            if (!poker.isUp()) {
                continue;
            }
            poker.setUp(false);
            poker.turnRear();
        }
    }


    /**
     * 显示地主牌并且将他放到地主的手牌集合中
     * @param dzPokerList 地主手牌集合
     */
    public static void showAndGetDZPoker(ArrayList<Poker> dzPokerList) {
        //将地主手牌 翻面展示
        for (Poker poker : dzPokerList) {
            poker.setUp(true);
            poker.turnFront();
        }
    }


    /**
     * 获得地主手牌
     * @param player 玩家  (地主玩家)
     */
    public static void getLandOwnerPoker(Player player) {
        //标识符id
        String ownerId;
        //根据地主玩家 设置 地主牌标识符
        if (player instanceof RealPlayer) {
            ownerId = "REAL";
        } else if (player instanceof ComputerB) {
            ownerId = "CPB";
        } else {
            ownerId = "CPA";
        }

        GameController controller = GameController.getInstance();
        ArrayList<Poker> dzPokerList = controller.getLandOwnerPokerList();
        for (Poker poker : dzPokerList) {
            if (player instanceof RealPlayer) {
                poker.setCanBeClick(true);
            }
            poker.setOwnerId(ownerId);
            player.getPokerList().add(poker);
        }

        //重新排序
        sortPoker(player);
        //卡牌位置再次随着大小排序移动
        pokerMove(player);
    }

    /**
     * 重新发牌
     */
    public static void reDealPoker() {
        GameController gameController = GameController.getInstance();
        //首先把三个玩家的手牌清空
        gameController.getPlayer().getPokerList().clear();
        gameController.getComputerA().getPokerList().clear();
        gameController.getComputerB().getPokerList().clear();
        //将牌桌上的牌清空
        gameController.getNowDeskPokerList().clear();
        //将玩家 出牌集合中的牌清空
        gameController.getPlayer().getDiscardPokerList().clear();
        gameController.getComputerA().getDiscardPokerList().clear();
        gameController.getComputerB().getDiscardPokerList().clear();
        //清空地主牌集合
        gameController.getLandOwnerPokerList().clear();
        //把牌堆再次打乱然后重新在面板中画出 以及 重新生成地主牌集合
        ArrayList<Poker> pokerBoxList = gameController.getPokerBoxList();
        Collections.shuffle(pokerBoxList);
        //重置卡牌
        ResetPokerList(pokerBoxList);
        //生成地主牌集合
        getDZPoker();
        //再次画出打乱以及重置后的牌盒
        painPoker();
        //将控制器中当前发牌索引设置为0
        gameController.setCurrentPokerIndex(0);
        //重新启动发牌定时器
        gameController.getDealCardsTimer().getTimer().start();
    }


    /**
     * 判断扑克牌类型 (对子、三张、炸弹等等)
     * @param pokerList 出牌集合
     * @return 扑克牌类型
     */
    public static PokerType judgePokerType(ArrayList<Poker> pokerList) {


        Collections.sort(pokerList, new Comparator<Poker>() {
            @Override
            public int compare(Poker o1, Poker o2) {
                return o2.getNumber() - o1.getNumber();
            }
        });


        int len = pokerList.size();
        //依靠集合中牌的数量 初步确立牌型范围

        // 数量小于等于4如果 扑克数量小于等于 4
        if (len <= 4) {
            //第一张和最后一张的数值相等 那么牌型可能是（单张、对子、三张、炸弹）
            if (len > 0 && pokerList.get(0).getNumber() == pokerList.get(len - 1).getNumber()) {
                switch (len) {
                    // 数量为1 单张
                    case 1:
                        return PokerType.P1;
                    // 数量为2 对子
                    case 2:
                        return PokerType.P2;
                    // 数量为2 三张
                    case 3:
                        return PokerType.P3;
                    // 数量为4 炸弹
                    case 4:
                        return PokerType.P4;
                }
            }
            //数量为2 第1、2张卡牌花色为5(大小王) 那么 类型为 王炸
            else if (len == 2 && getColor(pokerList.get(1)) == 5 && getColor(pokerList.get(0)) == 5) {
                return PokerType.P4;
            }
            //如果 数量为4 第一张和倒数第二张相同 或者 最后一张和第二张相同
            else if (len == 4 && (pokerList.get(0).getNumber() == pokerList.get(len - 2).getNumber() || pokerList.get(len - 1).getNumber() == pokerList.get(1).getNumber())) {
                //返回牌型  3带1
                return PokerType.P31;
            } else {
                return PokerType.P0;
            }
        }

        //如果卡牌数量大于五 可能的牌型(3带2、 4带1对（或许 两个单张）、  4带2对、顺子、连对、飞机)
        if (len >= 5) {
            PokerIndex pokerIndex = new PokerIndex();
            ArrayList<ArrayList<Integer>> indexList = pokerIndex.indexList;

            for (int i = 0; i < 4; i++) {
                indexList.add(new ArrayList<>());
            }

            getPokerNumber(pokerIndex, pokerList);
            if (len == 5 && indexList.get(1).size() == 1 && indexList.get(2).size() == 1) { //代表 牌数量是否为5 有3张相同的牌  2张相同的牌
                //返回 类型 3带2
                return PokerType.P32;
            }

            if (len == 6 && indexList.get(3).size() == 1) { // 代表 牌数量是否 为6 有4张相同的牌
                //返回 类型 4带一对（或者两张单张）
                return PokerType.P411;
            }

            if (len == 8 && indexList.get(3).size() == 1 && indexList.get(1).size() == 2) { // 代表 牌数量是否为8 有4张相同的牌 两对相同的牌
                //返回 类型 4带2对
                return PokerType.P422;
            }

            if (getColor(pokerList.get(len - 1)) != 5 && indexList.get(0).size() == len && indexList.get(0).get(len - 1) < 13 && indexList.get(0).get(len - 1) - indexList.get(0).get(0) == len - 1) { //代表  单张牌集合中最后一张的花色不是5(大小王)  牌的数量等于单张扑克牌的数量 以及 第最后一张牌（也就是最大的单排）的值要小于 小丑牌 以及 顺子是有序的
                //返回 类型 顺子
                return PokerType.P12345;
            }

            if (indexList.get(1).size() == len / 2 && len / 2 >= 3 && len % 2 == 0
                    && (pokerList.get(0).getNumber() - pokerList.get(len - 1).getNumber()) == len / 2 - 1) {
                //代表 对子的数量是否等于 扑克牌数量的一半 且 扑克牌数量 整除2 是否大于3 且 扑克牌求余2是否等于0 且 扑克牌集合中第一张牌的值减去 最后一张牌的值 是否等于 扑克牌集合的 数量整除2 -1 （即连对是有序的）
                // 返回 扑克牌类型 连对
                return PokerType.P112233;
            }

            if (indexList.get(2).size() == len / 3 && len % 3 == 0 && (pokerList.get(len - 1).getNumber() - pokerList.get(0).getNumber()) == len / 3 - 1) {
                //如果 三张牌数量等于 扑克牌集合数量 整除 3 且 扑克牌数量 求余 3 等于0 且 扑克牌集合中第一张牌的值减去 最后一张牌的值 是否等于 扑克牌集合的 数量整除3 -1 （即飞机是有序的）
                //返回 牌型飞机 （不带牌的）
                return PokerType.P111222;
            }
            if (indexList.get(2).size() == len / 4 && (indexList.get(2).get(len / 4 - 1)) - (indexList.get(2).get(0)) == len / 4 - 1
                    && ((indexList.get(0).size() == indexList.get(2).size() || indexList.get(1).size() == 1)) && len == 8 && indexList.get(2).get(len / 4 - 1) < 13) {
                //如果 三张牌的数量 等于 牌集合数量 整除4 且 计数集合中 三张牌的的最大的那三张牌的值 - 最小的三张牌的值 等于 总牌数 整除4 -1（确保 三张 是有序的）
                //返回 牌型 飞机（带2张单牌 或 1个对子）
                return PokerType.P11122234;
            }
            if (indexList.get(2).size() == len / 4 && ((indexList.get(2).get(len / 4 - 1)) - (indexList.get(2).get(0)) == len / 4
                    - 1) && (indexList.get(1).size() == indexList.get(2).size() || indexList.get(0).size() == indexList.get(2).size())) {

                //返回 牌型 飞机（3334446677 或 333444555 678 或 333444555667788）
                return PokerType.P1112223344;
            }


        }


        return PokerType.P0;

    }

    /**
     * 获得花色
     * @param poker 扑克牌
     * @return 花色类型
     */
    public static int getColor(Poker poker) {
        return Integer.parseInt(poker.getName().substring(0, 1));
    }


    /**
     * 对扑克牌计数
     * @param pokerIndex 存放不同牌值的数量的集合 统计有多少张相同大小的牌
     * @param pokerList 扑克牌集合
     */
    public static void getPokerNumber(PokerIndex pokerIndex, ArrayList<Poker> pokerList) {
        int count[] = new int[14]; //3~小丑牌 一共14种


        for (Poker poker : pokerList) {
            if (getColor(poker) == 5) { //如果是 小丑牌 那么特殊处理
                count[13]++;
            } else {
                //根据 扑克牌值的大小存放到对应位置
                count[poker.getNumber() - 1]++;
            }
        }

        ArrayList<ArrayList<Integer>> indexList = pokerIndex.indexList;
        for (int i = 0; i < 14; i++) {
            switch (count[i]) {
                case 1: // 计数为1，表示只有一张这种值的牌
                    indexList.get(0).add(i + 1); // 将该牌值 添加到单张牌的列表中
                    break;
                case 2: // 计数为2，表示有2张这种值的牌
                    indexList.get(1).add(i + 1);
                    break;
                case 3: // 计数为3，表示有3张这种值的牌
                    indexList.get(2).add(i + 1);
                    break;
                case 4: // 计数为4，表示有4张这种值的牌
                    indexList.get(3).add(i + 1);
                    break;
            }
        }
    }

    /**
     * 根据牌型 获取大小
     * @param pokerList 扑克牌集合
     * @param pokerType 牌型
     * @return 大小
     */
    public static int calculatePokerValueBasedOnType(ArrayList<Poker> pokerList, PokerType pokerType) {


        // 检查扑克牌列表是否为空 且 牌型不对
        if (pokerList == null || pokerList.isEmpty() && pokerType == PokerType.P0) {
            return -1; // 返回-1表示无效输入
        }

        // 如果数量小于5
        // 针对 P1 和 P2 类型，返回第一张牌的数值
        if (pokerType == PokerType.P1 || pokerType == PokerType.P2) {
            return pokerList.get(0).getNumber();
        }

        PokerIndex pokerIndex = new PokerIndex();

        for (int i = 0; i < 4; i++) {
            pokerIndex.indexList.add(new ArrayList<>());
        }

        getPokerNumber(pokerIndex, pokerList);

        // 如果是 3 张 或者 3 带 1、3 带 2
        if (pokerType == PokerType.P3 || pokerType == PokerType.P31 || pokerType == PokerType.P32) {
            return pokerIndex.indexList.get(2).get(0); // 返回 3 张牌的数值
        }

        // 如果是 牌型是炸弹
        if (pokerType == PokerType.P4) {
            // 如果颜色为 5，返回最大整数，表示炸弹
            if (getColor(pokerList.get(0)) == 5) {
                return Integer.MAX_VALUE;
            } else {
                return pokerIndex.indexList.get(3).get(0); // 返回 4 张牌的数值
            }
        }

        // 如果是 4 张带 2个单牌 或 4 张带 2对
        if (pokerType == PokerType.P411 || pokerType == PokerType.P422) {
            return pokerIndex.indexList.get(3).get(0); // 返回 4 张牌的数值
        }

        // 如果是顺子，返回最后一张牌的数值
        if (pokerType == PokerType.P12345) {
            return pokerIndex.indexList.get(0).get(0); // 返回顺子的最小值
        }

        //如果是 飞机 返回飞机最小的那个三张的值
        if (pokerType == PokerType.P1112223344 || pokerType == PokerType.P111222 || pokerType == PokerType.P11122234) {
            return pokerIndex.indexList.get(2).get(0); //返回飞机中 三张的最小的值
        }


        return -1;

    }

    /**
     * 获取单牌
     * @param player 玩家
     * @param deskPokerList 牌集合
     */
    public static void  getSingle(Player player, ArrayList<Poker> deskPokerList) {
        //从玩家手牌中 选出 比牌桌上牌大的单牌
        //优先选则单张牌子
        PokerIndex pokerIndex = new PokerIndex();
        for (int i = 0; i < 4; i++) {
            pokerIndex.indexList.add(new ArrayList<>());
        }
        //计算桌面上单张牌的大小
        int deskPokerValue = calculatePokerValueBasedOnType(deskPokerList, PokerType.P1);
        getPokerNumber(pokerIndex,player.getPokerList());
        //创建临时集合
        ArrayList<Poker> tempPokerList = new ArrayList<>();
        //遍历玩家手牌集合
        for (Poker poker : player.getPokerList()) {
            //寻找玩家手牌中 大于牌桌上的牌 并且大于等于单牌集合中最小的单排（即找到大于桌面上单排 又是 玩家手牌中 单张牌里面最小的）
            if (poker.getNumber() > deskPokerValue) {
                tempPokerList.add(poker);
            }
        }
        if (!tempPokerList.isEmpty()) {
            //将最小的牌添加至 出牌集合当中
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 1));
        }
    }

    /**
     * 获取对子
     * @param player 玩家
     * @param pokerList 牌集合
     */

    public static void getTwo(Player player, ArrayList<Poker> pokerList) {
        //获取玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();
        //检查 玩家手牌数量是否大于2 不大于直接结束
        if (playerPokerList.size() < 2) {
            return;
        }
        //创建临时集合
        ArrayList<Poker> tempPokerList = new ArrayList<>();

        //遍历手牌集合
        for (int i = 0; i < playerPokerList.size() - 1; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber()) {
                if (playerPokerList.get(i).getNumber() > pokerList.get(0).getNumber()) {
                    tempPokerList.add(playerPokerList.get(i));
                    tempPokerList.add(playerPokerList.get(i + 1));
                }
                i++;
            }
        }

        //将最后的对子添加到 出牌集合当中
        if (tempPokerList.size() > 1) {
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 1));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 2));
        }

    }


    /**
     * 获取单牌
     * @param player 玩家
     * @param pokerList 牌集合
     */
    public static void getThree(Player player, ArrayList<Poker> pokerList) {
        //获取玩家当前手牌
        ArrayList<Poker> playerPokerList = player.getPokerList();
        //如果当前手牌 数量小于2那么直接结束
        if (playerPokerList.size() < 3) {
            return;
        }
        // 创建临时集合，用于存储找到的三张相同的牌
        ArrayList<Poker> tempList = new ArrayList<>();

        // 遍历玩家手牌
        for (int i = 0; i < playerPokerList.size() - 2; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 2).getNumber()) {
                // 找到三张相同的牌
                if (playerPokerList.get(i).getNumber() > pokerList.get(0).getNumber()) {
                    tempList.add(playerPokerList.get(i));
                    tempList.add(playerPokerList.get(i + 1));
                    tempList.add(playerPokerList.get(i + 2));
                }
                i += 2; // 跳过这三张
            }
        }

        if (tempList.size() > 2) {
            player.getDiscardPokerList().add(tempList.get(tempList.size() - 1));
            player.getDiscardPokerList().add(tempList.get(tempList.size() - 2));
            player.getDiscardPokerList().add(tempList.get(tempList.size() - 3));
        }
    }

    /**
     * 获取炸弹
     * @param player 玩家
     * @param pokerList 牌的集合
     * @param pokerListType 牌的牌型
     */
    public static void getBoom(Player player, ArrayList<Poker> pokerList, PokerType pokerListType) {
        //获取玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();
        //创建临时集合1 存放比 符合桌面牌型的炸弹
        ArrayList<Poker> tempPokerList1 = new ArrayList<>();
        //创建临时集合2
        ArrayList<Poker> tempPokerList2 = new ArrayList<>();

        //判断 玩家手牌集合中 手牌数量是否小于4
        if (playerPokerList.size() < 4) {
            //判断 玩家手牌中是否有王炸
            if (getColor(playerPokerList.get(0)) == 5 && getColor(playerPokerList.get(1)) == 5) {
                //有王炸 加入临时集合
                tempPokerList1.add(playerPokerList.get(0));
                tempPokerList1.add(playerPokerList.get(1));
            }
            //将临时集合中的牌 放入出牌集合
            player.getDiscardPokerList().addAll(tempPokerList1);
            return;
        }


        // 遍历玩家手牌
        for (int i = 0; i < playerPokerList.size() - 3; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 2).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 3).getNumber()) {
                // 找到四张相同的牌
                tempPokerList2.add(playerPokerList.get(i));
                tempPokerList2.add(playerPokerList.get(i + 1));
                tempPokerList2.add(playerPokerList.get(i + 2));
                tempPokerList2.add(playerPokerList.get(i + 3));

                //判断当前桌上的牌是否是炸弹
                if (pokerListType == PokerType.P4) {
                    //获取当前牌桌上 炸弹的 数值大小
                    int nowDeskPokerValue = calculatePokerValueBasedOnType(pokerList, pokerListType);
                    //判断 临时集合2中的炸弹 是否 比 牌桌上的 炸弹 大
                    int tempValue = calculatePokerValueBasedOnType(tempPokerList2, PokerType.P4);
                    //如果临时集合2中的炸弹 的数值大于牌桌上的炸弹 那么 将临时集合2 的炸弹放入 临时集合1
                    if (tempValue > nowDeskPokerValue) {
                        tempPokerList1.addAll(tempPokerList2);
                        //清空临时集合2
                        tempPokerList2.clear();
                        i += 3; // 跳过这三张
                    } else {//不大于 直接结束 因为是从大的牌开始往小的牌寻找 最大的炸弹 不大于 牌桌上的 那么直接结束
                        //检测是否有火箭 有则加入 要出的牌的集合
                        getRocket(player);
                        return;
                    }
                } else { //当前牌桌上不是炸弹
                    tempPokerList1.addAll(tempPokerList2);
                    i += 3;
                }
            }
        }

        //获取 手牌中 最小的炸弹
        if (tempPokerList1.size() > 3) {
            player.getDiscardPokerList().add(tempPokerList1.get(tempPokerList1.size() - 1));
            player.getDiscardPokerList().add(tempPokerList1.get(tempPokerList1.size() - 2));
            player.getDiscardPokerList().add(tempPokerList1.get(tempPokerList1.size() - 3));
            player.getDiscardPokerList().add(tempPokerList1.get(tempPokerList1.size() - 4));
        }
        if (player.getDiscardPokerList().isEmpty()) {
            //最后 牌桌上既不是炸弹 手牌中也没有炸弹 查看是否有火箭
            getRocket(player);
        }

    }

    /**
     * 获得火箭
     */
    public static void getRocket(Player player) {
        //获得玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();
        //判断 玩家手牌中是否有王炸
        if (getColor(playerPokerList.get(0)) == 5 && getColor(playerPokerList.get(1)) == 5) {
            //有王炸 加入出牌集合
            player.getDiscardPokerList().add(playerPokerList.get(0));
            player.getDiscardPokerList().add(playerPokerList.get(1));
        }
    }


    /**
     * 获取三带一
     * @param player 出牌玩家
     * @param nowDeskPokerList 牌桌上牌集合
     */

    public static void getThreeOne(Player player, ArrayList<Poker> nowDeskPokerList) {
        //获取玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();

        PokerIndex pokerIndex = new PokerIndex();

        for (int i = 0; i < 4; i++) {
            pokerIndex.indexList.add(new ArrayList<>());
        }

        //统计当前手牌 情况
        getPokerNumber(pokerIndex, playerPokerList);

        if (playerPokerList.size() < 4 || pokerIndex.indexList.get(2).isEmpty()) { //数量小于4 或 三张集合牌的数量 为空
            return; //结束
        }


        //获取 牌桌上三张牌大小
        int deskPokerValue = calculatePokerValueBasedOnType(nowDeskPokerList, PokerType.P31);


        // 创建临时集合，用于存储找到的三张相同的牌
        ArrayList<Poker> tempPokerList = new ArrayList<>();

        // 遍历玩家手牌
        for (int i = 0; i < playerPokerList.size() - 2; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 2).getNumber()) {
                // 找到三张相同的牌
                //大小比 deskPokerValue 大
                if (playerPokerList.get(i).getNumber() > deskPokerValue) {
                    tempPokerList.add(playerPokerList.get(i));
                    tempPokerList.add(playerPokerList.get(i + 1));
                    tempPokerList.add(playerPokerList.get(i + 2));
                }
                i += 2; // 跳过这三张
            }
        }

        if (tempPokerList.size() > 2) {
            //获取最小的那三张牌
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 1));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 2));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 3));
            //获取单张牌 最小的那张
            for (int i = playerPokerList.size() - 1; i >= 0; i--) {
                if (playerPokerList.get(i).getNumber() == pokerIndex.indexList.get(0).get(0)) {
                    player.getDiscardPokerList().add(playerPokerList.get(i));
                    break;
                }
            }
        }

    }


    /**
     * 获取三带二
     * @param player 出牌玩家
     * @param nowDeskPokerList 牌桌上牌集合
     */
    public static void getThreeTwo(Player player, ArrayList<Poker> nowDeskPokerList) {
        //获取玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();

        PokerIndex pokerIndex = new PokerIndex();

        for (int i = 0; i < 4; i++) {
            pokerIndex.indexList.add(new ArrayList<>());
        }

        //统计当前手牌 情况
        getPokerNumber(pokerIndex, playerPokerList);

        if (playerPokerList.size() < 5 || pokerIndex.indexList.get(2).isEmpty() || pokerIndex.indexList.get(1).isEmpty()) { //数量小于5 或者 三张牌集合为空 对子集合为空
            return; //结束
        }

        //获取 牌桌上三张牌大小
        int deskPokerValue = calculatePokerValueBasedOnType(nowDeskPokerList, PokerType.P32);

        // 创建临时集合，用于存储找到的三张相同的牌
        ArrayList<Poker> tempPokerList = new ArrayList<>();

        // 遍历玩家手牌
        for (int i = 0; i < playerPokerList.size() - 2; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 2).getNumber()) {
                // 找到三张相同的牌
                //大小比 deskPokerValue 大
                if (playerPokerList.get(i).getNumber() > deskPokerValue) {
                    tempPokerList.add(playerPokerList.get(i));
                    tempPokerList.add(playerPokerList.get(i + 1));
                    tempPokerList.add(playerPokerList.get(i + 2));
                }
                i += 2; // 跳过这三张
            }
        }

        if (tempPokerList.size() > 2) {
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 1));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 2));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 3));
            for (int i = playerPokerList.size() - 1; i >= 0; i--) {
                //获取 手牌中 对子最小的
                if (playerPokerList.get(i).getNumber() == pokerIndex.indexList.get(1).get(0)) {
                    player.getDiscardPokerList().add(playerPokerList.get(i));
                    player.getDiscardPokerList().add(playerPokerList.get(i - 1));
                    break;
                }
            }
        }
    }


    /**
     * 获取四带2
     * @param player 出牌玩家
     * @param pokerList 扑克牌集合
     */
    public static void getFourOneOne(Player player, ArrayList<Poker> pokerList) {
        //获取玩家手牌集合
        ArrayList<Poker> playerPokerList = player.getPokerList();


        PokerIndex pokerIndex = new PokerIndex();

        for (int i = 0; i < 4; i++) {
            pokerIndex.indexList.add(new ArrayList<>());
        }

        //统计当前手牌 情况
        getPokerNumber(pokerIndex, playerPokerList);

        if (playerPokerList.size() < 6 || pokerIndex.indexList.get(3).isEmpty()) { //玩家手牌 数量小于 6 或者 玩家手牌上没有四张值一样的牌
            return;
        }

        //获取 牌桌上牌大小
        int deskPokerValue = calculatePokerValueBasedOnType(pokerList, PokerType.P411);

        // 创建临时集合，用于存储找到的四张相同的牌
        ArrayList<Poker> tempPokerList = new ArrayList<>();


        // 遍历玩家手牌
        for (int i = 0; i < playerPokerList.size() - 3; i++) {
            if (playerPokerList.get(i).getNumber() == playerPokerList.get(i + 1).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 2).getNumber() &&
                    playerPokerList.get(i).getNumber() == playerPokerList.get(i + 3).getNumber()) {
                // 找到四张相同的牌
                //大小比 deskPokerValue 大
                if (playerPokerList.get(i).getNumber() > deskPokerValue) {
                    tempPokerList.add(playerPokerList.get(i));
                    tempPokerList.add(playerPokerList.get(i + 1));
                    tempPokerList.add(playerPokerList.get(i + 2));
                    tempPokerList.add(playerPokerList.get(i + 3));
                }
                i += 3; // 跳过这三张
            }
        }

        if (tempPokerList.size() > 3) {

            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 1));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 2));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 3));
            player.getDiscardPokerList().add(tempPokerList.get(tempPokerList.size() - 4));

            int singleIndex = 0;
            for (int i = playerPokerList.size() - 1; i >= 0; i--) {
                if (!pokerIndex.indexList.get(1).isEmpty()) { //有对子拿对子凑
                    //获取 手牌中 对子最小的
                    if (playerPokerList.get(i).getNumber() == pokerIndex.indexList.get(1).get(0)) {
                        player.getDiscardPokerList().add(playerPokerList.get(i));
                        player.getDiscardPokerList().add(playerPokerList.get(i - 1));
                        break;
                    }
                } else { //没有 就单牌
                    if (playerPokerList.get(i).getNumber() == pokerIndex.indexList.get(0).get(singleIndex++)) {
                        player.getDiscardPokerList().add(playerPokerList.get(i));
                    }
                    if (singleIndex > 1) {
                        break;
                    }
                }
            }
        }

    }


    /**
     * 顺子
     * @param player 出牌玩家
     * @param pokerList 扑克牌集合
     */

    public static void getP12345(Player player, ArrayList<Poker> pokerList) {
        //获得玩家手牌
        ArrayList<Poker> playerPokerList = player.getPokerList();
        //玩家手牌 数量小于 5张 直接返回
        if (playerPokerList.size() < 5) {
            return;
        }

        //计算牌桌 牌的值
        int deskPokerValue = calculatePokerValueBasedOnType(pokerList, PokerType.P12345);
        //创建临时集合
        ArrayList<Poker> tempPokerList = new ArrayList<>();


        //获得 牌桌上顺子的长度
        int size = pokerList.size();
        for (int i = playerPokerList.size() - 1; i >= 0; i--) {
            //判断 扑克牌的值是否大于 牌桌上顺子的值（牌桌上顺子最小牌的值） 并且 扑克牌的值 小于 13（即最大不能到 2）
            if (playerPokerList.get(i).getNumber() > deskPokerValue && playerPokerList.get(i).getNumber() < 13) {
                //牌集合是 从大到小 排序 所以 从后往前判断  相邻的牌是否 差值为1
                if (i - 1 >= 0 && playerPokerList.get(i - 1).getNumber() - playerPokerList.get(i).getNumber() == 1) {
                    //添加扑克牌到临时集合
                    tempPokerList.add(playerPokerList.get(i));
                    //长度 -1
                    size--;
                } else {
                    //如果 差值 不唯一 那么判断 相邻的牌是否相等
                    if (i - 1 >= 0 && playerPokerList.get(i - 1).getNumber() != playerPokerList.get(i).getNumber()) {
                        //不相等 清空集合
                        tempPokerList.clear();
                        //长度重置
                        size = pokerList.size();
                        if (size - i - 1 > 0) {
                            break;
                        }
                    }
                }
            }
            //如果 长度小于等于0结束
            if (size <= 0) {
                break;
            }
        }

        //最后判断 如果长度相等 将临时集合中的牌 赋给 出牌集合
        if (tempPokerList.size() == pokerList.size()) {
            player.getDiscardPokerList().addAll(tempPokerList);
        }
    }


    /**
     * 自动出牌
     * @param curDiscardPokerPlayer 当前出牌玩家
     * @param deskPokerList 当前牌桌上的牌
     */
    public static void autoDiscardPoker(Player curDiscardPokerPlayer, ArrayList<Poker> deskPokerList) {
        //获取当前玩家 身份 （实际玩家、电脑A、电脑B）
        //卡牌标识符 （用来判断 当前牌桌上的卡牌是否是当前玩家出的）
        String ownerId;

        if (curDiscardPokerPlayer instanceof RealPlayer) {
            ownerId = "REAL";
        } else if (curDiscardPokerPlayer instanceof ComputerB) {
            ownerId = "CPB";
        } else {
            ownerId = "CPA";
        }

        //判断 牌桌是的没有牌(代表玩家是地主第一个出牌)或者 当前牌桌上的牌是否 是 当前玩家 上一轮出的
        if (deskPokerList.isEmpty() || deskPokerList.get(0).getOwnerId().equals(ownerId)) {
            //如果是 当前玩家出的 那么 当前玩家可以任意出牌 只要出的牌型正确即可
            randomDiscardPoker(curDiscardPokerPlayer);
            finishDiscardPoker(curDiscardPokerPlayer, deskPokerList);
        } else {//不是自己出的 需要判断

            //获得当前 桌上手牌的类型
            PokerType deskPokerType = PokerUtil.judgePokerType(deskPokerList);

            //需要出和当前牌桌上对应类型的牌

            //首先查看当前手牌中 是否有配对的类型的牌   （炸弹可以应对任何类型）
            //判断牌桌上的牌是否是炸弹 如果是 那么调用获取炸弹牌型方法
            if (deskPokerType == PokerType.P4) {
                //调用获取炸弹方法
                getBoom(curDiscardPokerPlayer, deskPokerList, deskPokerType);
                if (!curDiscardPokerPlayer.getDiscardPokerList().isEmpty()) {
                    //倍数翻倍
                    JLabel multipleJLabel = GameUi.gameFrame.getGamePanel().getMultipleJLabel();
                    int multiple = Integer.parseInt(multipleJLabel.getText().substring(3));
                    multipleJLabel.setText("倍数：" + (multiple * 2));
                }
            } else { //不是炸弹 那么调用其他获取牌型方法
                switch (deskPokerType) {
                    //获取单张
                    case P1:
                        PokerUtil.getSingle(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取对子
                    case P2:
                        PokerUtil.getTwo(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取三张
                    case P3:
                        PokerUtil.getThree(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取三带一
                    case P31:
                        PokerUtil.getThreeOne(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取三带二
                    case P32:
                        PokerUtil.getThreeTwo(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取四带一对（两张单）
                    case P411:
                        PokerUtil.getFourOneOne(curDiscardPokerPlayer, deskPokerList);
                        break;
                    case P12345:
                        PokerUtil.getP12345(curDiscardPokerPlayer, deskPokerList);
                        break;
                    //获取四带二对
                    case P422:
                        break;
                }
                //二次判断 桌上牌型不是炸弹 但是手牌中没有与之对应的牌型 那么检测手牌是否有炸弹
                if (curDiscardPokerPlayer.getDiscardPokerList().isEmpty()) {
                    //调用获取炸弹方法
                    getBoom(curDiscardPokerPlayer, deskPokerList, deskPokerType);
                }
            }


            //查看 出牌集合中是否有牌
            //有 说明 手牌中有 类型和牌桌上的牌对应 并且大小 比牌桌上大的牌
            if (!curDiscardPokerPlayer.getDiscardPokerList().isEmpty()) {
                //执行出牌
                finishDiscardPoker(curDiscardPokerPlayer, deskPokerList);
            } else {//没有 （代表玩家手牌中没有可以应对桌上牌型的方法）
                //设置 完成出牌标志 true
                curDiscardPokerPlayer.setDiscardPokerOver(true);
                //游戏面板显示对应 不要标签
                if (curDiscardPokerPlayer instanceof RealPlayer) {
                    GameUi.gameFrame.getGamePanel().getRealNoDiscardJLabel().setText("不要");
                } else if (curDiscardPokerPlayer instanceof ComputerB) {
                    GameUi.gameFrame.getGamePanel().getComputerBNoDiscardJLabel().setText("不要");
                } else {
                    GameUi.gameFrame.getGamePanel().getComputerANoDiscardJLabel().setText("不要");
                }
            }
        }

    }


    /**
     * 完成出牌
     * @param curDiscardPokerPlayer 当前出牌玩家
     */
    public static void finishDiscardPoker(Player curDiscardPokerPlayer, ArrayList<Poker> deskPokerList) {
        GameUi.gameFrame.getGamePanel().resetNoDiscardPokerLabel();
        //检查是否 出的是炸弹 是的话 倍数翻倍
        checkDiscardBoom(curDiscardPokerPlayer.getDiscardPokerList());

        //设置出牌标志完成
        curDiscardPokerPlayer.setDiscardPokerOver(true);
        //将出出去的牌从手牌集合中移除
        curDiscardPokerPlayer.getPokerList().removeAll(curDiscardPokerPlayer.getDiscardPokerList());
        //移动 出牌集合中的牌
        moveDiscardPoker(curDiscardPokerPlayer);
        //如果当前出牌玩家是 电脑玩家 那么将他们出的牌 正面朝上
        if (curDiscardPokerPlayer instanceof ComputerA || curDiscardPokerPlayer instanceof ComputerB) {
            pokerUp(curDiscardPokerPlayer.getDiscardPokerList());
        }

        // 重新排序 并且 重绘玩家手牌
        PokerUtil.sortPoker(curDiscardPokerPlayer);
        PokerUtil.pokerMove(curDiscardPokerPlayer);

        //将当前牌桌上的牌 设置不可见
        for (Poker poker : deskPokerList) {
            poker.setVisible(false);
        }

        //更新 当前牌桌上的牌 为当前玩家出的牌
        deskPokerList.clear();
        deskPokerList.addAll(curDiscardPokerPlayer.getDiscardPokerList());

        //清空 玩家出牌的集合
        curDiscardPokerPlayer.getDiscardPokerList().clear();
        //将不要标签重置
        GameUi.gameFrame.getGamePanel().resetNoDiscardPokerLabel();
    }


    /**
     * 随机出牌
     * @param player 出牌玩家
     */
    public static void randomDiscardPoker(Player player) {
        player.getDiscardPokerList().add(player.getPokerList().get(player.getPokerList().size() - 1));
    }


    /**
     * 出牌提示方法
     * @param realPlayer 实际玩家
     * @param deskPokerList 牌桌上牌的集合
     */
    public static void promptDiscardPoker(RealPlayer realPlayer, ArrayList<Poker> deskPokerList) {
        //先将 出牌集合清空 避免 玩家点中 了牌 又点提示出现错误
        ArrayList<Poker> discardPokerList = realPlayer.getDiscardPokerList();

        if (!discardPokerList.isEmpty()){
            //将之前选中的手牌降下
            pokerDown(discardPokerList);
            discardPokerList.clear();
        }


        //首先获得 当前牌桌上牌的牌型
        PokerType deskPokerType = judgePokerType(deskPokerList);

        //首先查看当前手牌中 是否有配对的类型的牌   （炸弹可以应对任何类型）
        //判断牌桌上的牌是否是炸弹 如果是 那么调用获取炸弹牌型方法
        if (deskPokerType == PokerType.P4) {
            //调用获取炸弹方法
            getBoom(realPlayer, deskPokerList, deskPokerType);
        } else {
            //不是炸弹 那么调用其他获取牌型方法
            switch (deskPokerType) {
                //获取单张
                case P1:
                    PokerUtil.getSingle(realPlayer, deskPokerList);
                    break;
                //获取对子
                case P2:
                    PokerUtil.getTwo(realPlayer, deskPokerList);
                    break;
                //获取三张
                case P3:
                    PokerUtil.getThree(realPlayer, deskPokerList);
                    break;
                //获取三带一
                case P31:
                    PokerUtil.getThreeOne(realPlayer, deskPokerList);
                    break;
                //获取三带二
                case P32:
                    PokerUtil.getThreeTwo(realPlayer, deskPokerList);
                    break;
                //获取四带一对（两张单）
                case P411:
                    PokerUtil.getFourOneOne(realPlayer, deskPokerList);
                    break;
                case P12345:
                    PokerUtil.getP12345(realPlayer, deskPokerList);
                    break;
                //获取四带二对
                case P422:
                    break;
            }
            //二次判断 桌上牌型不是炸弹 但是手牌中没有与之对应的牌型 那么检测手牌是否有炸弹
            if (realPlayer.getDiscardPokerList().isEmpty()) {
                //调用获取炸弹方法
                getBoom(realPlayer, deskPokerList, deskPokerType);
            }
        }


        //将 出牌集合手的手牌 弹出 如果有的话
        if (!discardPokerList.isEmpty()){
            pokerUp(discardPokerList);
        }

        //升起对应扑克牌
        realPlayer.upDiscardPoker(discardPokerList);

    }
}

